#pragma once
#include <iostream>
#include <jsoncpp/json/json.h>

#include "compiler.hpp"
#include "runner.hpp"
#include "../com/util.hpp"
#include "../com/log.hpp"

namespace lh_com_run
{
    using namespace lh_compiler;
    using namespace lh_runner;
    using namespace lh_util;
    using namespace lh_log;
    class CompileRun
    {
    public:
        CompileRun() {}
        ~CompileRun() {}
        static std::string StatusToReason(int status, const std::string &file_name)
        {
            std::string ret;
            switch (status)
            {
            case -1:
                ret = "用户输入代码为空";
                break;
            case -2:
                ret = "内部错误";
                break;
            case -3:
                FileUtil::ReadFile(PathUtil::CompileErr(file_name), &ret);
                break;
            case 0:
                ret = "编译-运行成功";
                break;
            case 6:
                ret = "程序运行超出时间限制";
                break;
            case 24:
                ret = "程序运行超出空间限制";
                break;
            case 11:
                ret = "程序发生段错误";
                break;
            default:
                ret = "unknow";
                break;
            }
            return ret;
        }
        static void RemoteTempFile(const std::string &file_name)
        {
            //.cpp
            std::string src = PathUtil::Src(file_name);
            if (FileUtil::IsExist(src))
                unlink(src.c_str());
            //.exe
            std::string exe = PathUtil::Exe(file_name);
            if (FileUtil::IsExist(exe))
                unlink(exe.c_str());
            //.comerr
            std::string comerr = PathUtil::CompileErr(file_name);
            if (FileUtil::IsExist(comerr))
                unlink(comerr.c_str());
            //.in
            std::string in = PathUtil::In(file_name);
            if (FileUtil::IsExist(in))
                unlink(in.c_str());
            //.out
            std::string out = PathUtil::Out(file_name);
            if (FileUtil::IsExist(out))
                unlink(out.c_str());
            //.err
            std::string err = PathUtil::Err(file_name);
            if (FileUtil::IsExist(err))
                unlink(err.c_str());
        }
        // 对in_json反序列化 -> 形成临时文件 -> 编译 -> 运行 -> 构建out_json 返回
        /* -----------------------------------------------------------------
         * in_json:
         *  1. code  代码
         *  2. input 输入信息
         *  3. cpu_limit 时间限制
         *  4. mem_limit 空间限制
         *
         * out_json:
         *  1. status 状态码
         *  2. reason 原因
         *  3. stdout 标准输出
         *  4. stderr 标准错误
         * ------------------------------------------------------------------*/
        static void start(const std::string &in_json, std::string *out_json)
        {

            out_json->clear();
            // 1. in_json 反序列化
            Json::Value in_val, out_val;
            Json::Reader reader;
            // reader.parse(in_json, in_val);
            if (!reader.parse(in_json, in_val))
            {
                LOG(ERROR) << "JSON 解析失败: " << reader.getFormattedErrorMessages();
                return;
            }
            std::string code = in_val["code"].asString();
            std::string input = in_val["input"].asString();
            int cpu_limit = in_val["cpu_limit"].asInt();
            int mem_limit = in_val["mem_limit"].asInt();
            int status = 0;
            std::string file_name; // 形成临时文件的唯一文件名
            int run_result;        // 调用运行Run的返回值
            if (code.empty())
            {
                status = -1;
                goto END;
            }
            // std::cout << "形成临时文件" << std::endl;
            // 2. 形成临时文件
            /* 获取唯一文件名 -> 将code写入文件中*/
            file_name = PathUtil::GetUniqueName();
            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
            {
                status = -2;
                goto END;
            }

            // 3. 编译
            if (!Compiler::Compile(file_name))
            {
                status = -3;
                goto END;
            }
            // 4. 运行
            run_result = Runner::Run(file_name, cpu_limit, mem_limit);
            if (run_result < 0)
            {
                status = -2;
            }
            else if (run_result == 0)
            {
                status = 0;
                std::string out;
                FileUtil::ReadFile(PathUtil::Out(file_name), &out,true);
                out_val["stdout"] = out;
                std::string err;
                FileUtil::ReadFile(PathUtil::Err(file_name), &err);
                out_val["stderr"] = err;
            }
            else
            {
                status = run_result;
            }
        END:
            out_val["status"] = status;
            out_val["reason"] = StatusToReason(status, file_name);
            // 序列化
            Json::FastWriter writer;
            *out_json = writer.write(out_val);
            RemoteTempFile(file_name);
        }

        /*static void start(const std::string &in_json, std::string *out_json)
        {
            // 1. in_json 反序列化
            Json::Value in_val;
            Json::Reader reader;
            Json::Value out_val;
            reader.parse(in_json, in_val);
            std::string code = in_val["code"].asString();
            std::string input = in_val["input"].asString();
            int cpu_limit = in_val["cpu_limit"].asInt();
            int men_limit = in_val["men_limit"].asInt();

            if (code.empty())
            {
                out_val["status"] = -1;
                out_val["reason"] = "用户输入的代码为空";
                // 序列化
                return;
            }

            // 2. 形成临时文件
            //获取唯一文件名 -> 将code写入文件中
            std::string file_name = PathUtil::GetUniqueName();
            if (!FileUtil::WriteFile(PathUtil::Src(file_name)))
            {
                out_val["status"] = -2;
                out_val["reason"] = "内部错误";
                // 序列化
                return;
            }

            // 3. 编译
            if (!Compiler::Compile(PathUtil::Src(file_name)))
            {
                out_val["status"] = -3;
                out_val["reason"] = FileUtil::ReadFile(PathUtil::CompileErr(file_name));
                // 序列化
                return;
            }

            // 4. 运行
            int run_result = Runner::Run(PathUtil::Exe(file_name), cpu_limit, men_limit);
            if (run_result < 0)
            {
                out_val["status"] = -2;
                out_val["reason"] = "内部错误";
                // 序列化
            }
            else if(run_result == 0)
            {
                out_val["status"] = 0;
                out_val["reason"] = "运行成功";
            }
            else
            {
                out_val["status"] = run_result;
                out_val["reason"] = GetSignal(run_result);
            }
        }*/
    };
}